local Frame = _ENV.import("./Element/Frame.lua")
local Window = commonlib.inherit(Frame);

Window:Property("WindowName");                        -- 窗口名
Window:Property("WindowPainter");                     -- 窗口绘图对象
Window:Property("Key");                               -- 唯一标识符
Window:Property("Destroy", false, "IsDestroy");       -- 是否销毁
Window:Property("Params");                            -- 窗口参数
Window:Property("RootWatchObject");                   -- 根监控对象
Window:Property("ZOrder", 0);                         -- z-order z轴序

Window:Property("MouseCaptureElement");               -- 鼠标捕获元素
Window:Property("FocusElement");                      -- 聚焦元素

-- 构造函数
function Window:ctor()
    self:SetClassName("Window");
    self:SetDestroy(false);
    self:SetWindowPainter(commonlib.GetWindowPainter());
    -- 窗口屏幕坐标及大小
    self.m_window_width, self.m_window_height = 0, 0;
end

-- 初始化函数
function Window:Init(params)
    params = params or {};

    self:SetRootWatchObject(commonlib.NewRootWatchObject(params.G));
    self:SetParams(params);
    self:SetWindowName(params.windowName);
    self:SetKey(params.key or params.windowName or params.url);
    self:SetZOrder(params.zorder or 0);
    self:InitWindowPosition();

    -- 子元素初始化
    Window._super.Init(self, {
        name = "window",
        attr = {
            id="window",
            template = params.template,
            url = params.url,
            style = {
                width = "100%",
                height = "100%",
            },
        },
    }, nil);

    return self;
end

-- 显示窗口
function Window:Show()
    self:SetDestroy(false);
    self:UpdateStyle();
    self:UpdateLayout();
    self:Render();
end

-- 关闭窗口
function Window:Close()
    if (self:IsDestroy()) then return end
    self:SetDestroy(true);
    local OnClosed = self:GetParams().OnClosed;
    if (type(OnClosed) == "function") then OnClosed(self) end
end

-- 获取窗口
function Window:GetWindow()
    return self;
end

-- 获取绘图
function Window:GetPainter()
    return self:GetWindowPainter();
end

-- 获取监控对象
function Window:GetWatchObject()
    return self:GetRootWatchObject();
end

-- 扩展全局函数 基类初始化会调用
function Window:ExtendG()
    local G = self:GetG();
    G.CloseWindow = function()
        self:Close();
    end
end

-- 刷新窗口
function Window:Refresh()
    self:GetRootWatchObject():TriggerWatchExprCallback();
end

function Window:Render()
    if (self:IsDestroy()) then return end
    self:Refresh();
    Window._super.Render(self);
end

function Window:OnSize()
    return self;
    -- self:InitWindowPosition();
    -- Window._super.Hide(self);
    -- Window._super.Show(self);
end

function Window:OnEvent(event)
    return self, event;
    -- local event_type = event:GetEventType();
    -- if (event_type == "onmousedown" or event_type == "onmousemove" or event_type == "onmouseup" or event_type == "onmousewheel") then 
    --     self:HandleMouseEvent(event);
    -- else 
    --     self:HandleKeyEvent(event);
    -- end
end

-- -- 获取方法名通过事件名
-- function Window:GetEventTypeFuncName(event)
--     local event_type = event:GetEventType();
--     if (event_type == "onmousedown") then
--         return "OnMouseDownCapture", "OnMouseDown";
--     elseif (event_type == "onmouseup") then
--         return "OnMouseUpCapture", "OnMouseUp";
--     elseif (event_type == "onmousemove") then
--         return "OnMouseMoveCapture", "OnMouseMove";
--     elseif (event_type == "onmousewheel") then
--         return "OnMouseWheelCapture", "OnMouseWheel";
--     else 
--         return "OnMouseCapture", "OnMouse";
--     end
-- end

-- local __event_element_list__ = {};  -- 事件元素列表
-- function Window:HandleMouseEvent(event)
--     local sx, sy = event:GetXY();
--     local event_type = event:GetEventType();
--     local target_el = self:GetMouseCaptureElement();
--     local captureFuncName, bubbleFuncName = self:GetEventTypeFuncName(event);
--     if (not target_el) then target_el = self:GetMouseElement(sx, sy) end 

--     -- 获取事件元素连
--     local size = 0;
--     local el = target_el;
--     commonlib.cleartable(__event_element_list__);
--     while (el) do
--         size = size + 1;
--         __event_element_list__[size] = el;
--         el = el:GetParent();
--     end

--     -- 捕获事件
--     for i = size, 1, -1 do
--         local el = __event_element_list__[i];
--         if (event:IsAccept()) then break end 
--         (el[captureFuncName])(el, event);
--     end

--     -- 冒泡事件
--     for i = 1, size, 1 do
--         local el = __event_element_list__[i];
--         if (event:IsAccept()) then break end 
--         (el[bubbleFuncName])(el, event);
--     end
    
--     -- 左键按下
--     if (event_type == "onmousedown") then 
--         if (event:IsLeftButton()) then event.__mouse_down_element__ = target_el end 
--     end 
    
--     -- 左键松开
--     if (event_type == "onmouseup") then 
--         if (event:IsLeftButton() and target_el and event.__mouse_down_element__ == target_el) then target_el:OnClick(event) end
--     end 

--     -- 接受事件
--     event:Accept();

--     self.SetActiveWindow(self);        
-- end

-- function Window:HandleKeyEvent(event)
--     local event_type = event:GetEventType();
--     local focus_el = self:GetFocusElement();
--     if (not focus_el) then return end 
--     if (event_type == "onkeydown") then
--         focus_el:OnKeyDown(event);
--     elseif (event_type == "onkeyup") then
--         focus_el:OnKeyUp(event);
--     elseif (event_type == "onchar") then
--         focus_el:OnChar(event);
--     else 
--     end
-- end

-- 初始化窗口的位置
function Window:InitWindowPosition()
    local params = self:GetParams();
    local windowX, windowY;
    local mainWindowWidth, mainWindowHeight = commonlib.GetWindowWidthHeight();
    local windowWidth, windowHeight = tonumber(params.width) or params.width or mainWindowWidth, tonumber(params.height) or params.height or mainWindowHeight;
    local offsetX, offsetY = tonumber(params.x) or params.x or 0, tonumber(params.y) or params.y or 0;
    if (type(windowWidth) == "string" and string.match(windowWidth, "^%d+%%$")) then windowWidth = math.floor(mainWindowWidth * tonumber(string.match(windowWidth, "%d+")) / 100) end
    if (type(windowHeight) == "string" and string.match(windowHeight, "^%d+%%$")) then windowHeight = math.floor(mainWindowHeight * tonumber(string.match(windowHeight, "%d+")) / 100) end
    if (type(offsetX) == "string" and string.match(offsetX, "^%d+%%$")) then offsetX = math.floor(mainWindowWidth * tonumber(string.match(offsetX, "%d+")) / 100) end
    if (type(offsetY) == "string" and string.match(offsetY, "^%d+%%$")) then offsetY = math.floor(mainWindowHeight * tonumber(string.match(offsetY, "%d+")) / 100) end

    if (params.alignment == "_ctb") then                 -- *	- "_ctb": align to center bottom of the screen
        windowX, windowY = offsetX + math.floor((mainWindowWidth - windowWidth) / 2), offsetY + mainWindowHeight - windowHeight;
    elseif (params.alignment == "_ctt") then             -- *	- "_ctt": align to center top of the screen
        windowX, windowY = offsetX + math.floor((mainWindowWidth - windowWidth) / 2), offsetY;
    elseif (params.alignment == "_ctl") then             -- *	- "_ctl": align to center left of the screen
        windowX, windowY = offsetX, offsetY + math.floor((mainWindowHeight - windowHeight) / 2);
    elseif (params.alignment == "_ctr") then             -- *	- "_ctr": align to center right of the screen
        windowX, windowY = offsetX + mainWindowWidth - windowWidth , offsetY + math.floor((mainWindowHeight - windowHeight) / 2);
    elseif (params.alignment == "_lt") then              -- *	- "_lt" align to left top of the screen
        windowX, windowY = offsetX, offsetY;
    elseif (params.alignment == "_lb") then              -- *	- "_lb" align to left bottom of the screen
        windowX, windowY = offsetX, offsetY + mainWindowHeight - windowHeight;
    elseif (params.alignment == "_rt") then              -- *	- "_rt" align to right top of the screen
        windowX, windowY = offsetX + mainWindowWidth - windowWidth, offsetY;
    elseif (params.alignment == "_rb") then              -- *	- "_rb" align to right bottom of the screen
        windowX, windowY = offsetX + mainWindowWidth - windowWidth, offsetY + mainWindowHeight - windowHeight;
    elseif (params.alignment == "_mt") then              -- *	- "_mt": align to middle top
        windowX, windowY = offsetX + math.floor((mainWindowWidth - windowWidth) / 2), offsetY;
    elseif (params.alignment == "_mb") then              -- *	- "_mb": align to middle bottom
        windowX, windowY = offsetX + math.floor((mainWindowWidth - windowWidth) / 2), offsetY + mainWindowHeight - windowHeight;
    elseif (params.alignment == "_ml") then              -- *	- "_ml": align to middle left
        windowX, windowY = offsetX, offsetY + math.floor((mainWindowHeight - windowHeight) / 2);
    elseif (params.alignment == "_mr") then              -- *	- "_mr": align to middle right
        windowX, windowY = offsetX + mainWindowWidth - windowWidth, offsetY + math.floor((mainWindowHeight - windowHeight) / 2);
    elseif (params.alignment == "_fi") then              -- *	- "_fi": align to left top and right bottom. This is like fill in the parent window.
        windowX, windowY, windowWidth, windowHeight = 0, 0, mainWindowWidth, mainWindowHeight;
    else                                                 -- *	- "_ct" align to center of the screen
        windowX, windowY = offsetX + math.floor((mainWindowWidth - windowWidth) / 2), offsetY + math.floor((mainWindowHeight - windowHeight) / 2);
    end
    self:SetWindowPosition(windowX, windowY, windowWidth, windowHeight)
    return windowX, windowY, windowWidth, windowHeight;
end

-- 设置窗口宽高
function Window:SetWindowWidthHeight(width, height)
    self.m_window_width, self.m_window_height = width or 0, height or 0;
end

-- 获取窗口宽高
function Window:GetWindowWidthHeight()
    return self.m_window_width or 0, self.m_window_height or 0;
end

-- 获取窗口位置
function Window:GetWindowPosition()
    local window_x, window_y = self:GetWindowXY();
    local window_width, window_height = self:GetWindowWidthHeight();
    return window_x, window_y, window_width, window_height;
end

-- 设置窗口位置
function Window:SetWindowPosition(x, y, width, height)
    self:SetWindowXY(x, y);
    self:SetWindowWidthHeight(width, height)
end

return Window;


